module aru_ub_rdgen_cfg_pipe (
    input logic                             clk,
    input logic                             rst_n,
          aru_ub_rdgen_cfg_if.in            u_aru_cfg_if,
          aru_ub_rdgen_cfg_if.crd_gen_out   u_aru_crd_gen_cfg_if,
          aru_ub_rdgen_cfg_if.addr_calc_out u_aru_addr_calc_cfg_if
);

    // Configuration pipeline depth
    localparam CFG_PIPE_DEPTH = 2;

    // Configuration index counter (to receive)
    logic [$clog2(CFG_PIPE_DEPTH)-1:0] cfg_idx_to_recv;
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cfg_idx_to_recv <= 'd0;
        end else begin
            if (u_aru_cfg_if.vld && u_aru_cfg_if.rdy) begin
                cfg_idx_to_recv <= cfg_idx_to_recv + 'd1;
            end
        end
    end

    // Configuration storage
    typedef struct packed {
        ub_addr_t ub_addr;
        idx_t     slice_m;
        idx_t     slice_n;
        logic     reduce_m;
        idx_t     instr_idx;
    } cfg_t;

    cfg_t cfg_slt[CFG_PIPE_DEPTH];
    logic cfg_vld[CFG_PIPE_DEPTH];
    logic [1:0] cfg_sent[CFG_PIPE_DEPTH];  // [0]: crd_gen sent, [1]: addr_calc sent

    // Configuration send indices
    logic [$clog2(CFG_PIPE_DEPTH)-1:0] cfg_idx_to_send_crd_gen;
    logic [$clog2(CFG_PIPE_DEPTH)-1:0] cfg_idx_to_send_addr_calc;

    // Single always_ff: handle receive (load), send (mark sent + advance indices), and clear when both sent
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            // reset all storage and pointers
            cfg_vld <= '{default: '0};
            for (integer i = 0; i < CFG_PIPE_DEPTH; i = i + 1) begin
                cfg_slt[i]  <= '0;
                cfg_sent[i] <= '0;
            end
            cfg_idx_to_send_crd_gen   <= 'd0;
            cfg_idx_to_send_addr_calc <= 'd0;
        end else begin
            // Default: keep current values (will be updated below as needed)
            // Loop over pipeline slots
            for (integer i = 0; i < CFG_PIPE_DEPTH; i = i + 1) begin
                // By default keep values (no unintended multiple drivers)
                cfg_slt[i]  <= cfg_slt[i];
                cfg_vld[i]  <= cfg_vld[i];
                cfg_sent[i] <= cfg_sent[i];

                // 1) If slot empty, possibly load new config when input valid & ready and index matches
                if (cfg_vld[i] == 1'b0) begin
                    if (u_aru_cfg_if.vld && u_aru_cfg_if.rdy && (i == cfg_idx_to_recv)) begin
                        cfg_slt[i].ub_addr   <= u_aru_cfg_if.ub_addr;
                        cfg_slt[i].slice_m   <= u_aru_cfg_if.slice_m;
                        cfg_slt[i].slice_n   <= u_aru_cfg_if.slice_n;
                        cfg_slt[i].reduce_m  <= u_aru_cfg_if.reduce_m;
                        cfg_slt[i].instr_idx <= u_aru_cfg_if.instr_idx;
                        cfg_vld[i]           <= 1'b1;
                        cfg_sent[i]          <= 2'b00;  // initialize sent bits for new entry
                    end
                end else begin
                    // 2) If both sent, clear this slot
                    if (cfg_sent[i] == 2'b11) begin
                        cfg_slt[i]  <= '0;
                        cfg_vld[i]  <= 1'b0;
                        cfg_sent[i] <= 2'b00;
                    end
                end
            end  // for

            // 3) Handle send-to-crd_gen: mark sent bit and advance send index
            if (u_aru_crd_gen_cfg_if.rdy) begin
                // only send if slot valid and not already sent for crd_gen
                if (cfg_vld[cfg_idx_to_send_crd_gen] && (cfg_sent[cfg_idx_to_send_crd_gen][0] == 1'b0)) begin
                    cfg_sent[cfg_idx_to_send_crd_gen][0] <= 1'b1;
                    cfg_idx_to_send_crd_gen              <= cfg_idx_to_send_crd_gen + 'd1;
                end
            end

            // 4) Handle send-to-addr_calc: mark sent bit and advance send index
            if (u_aru_addr_calc_cfg_if.rdy) begin
                if (cfg_vld[cfg_idx_to_send_addr_calc] && (cfg_sent[cfg_idx_to_send_addr_calc][1] == 1'b0)) begin
                    cfg_sent[cfg_idx_to_send_addr_calc][1] <= 1'b1;
                    cfg_idx_to_send_addr_calc              <= cfg_idx_to_send_addr_calc + 'd1;
                end
            end
        end  // else not reset
    end  // always_ff

    // u_aru_cfg_if backpressure: ready when next receive slot free
    assign u_aru_cfg_if.rdy = ~cfg_vld[cfg_idx_to_recv];

    // Output assignments for crd_gen (combinational view of current send index)
    assign u_aru_crd_gen_cfg_if.vld     = cfg_vld[cfg_idx_to_send_crd_gen] &&
                                          (cfg_sent[cfg_idx_to_send_crd_gen][0] == 1'b0);
    assign u_aru_crd_gen_cfg_if.reduce_m = cfg_slt[cfg_idx_to_send_crd_gen].reduce_m;
    assign u_aru_crd_gen_cfg_if.slice_m = cfg_slt[cfg_idx_to_send_crd_gen].slice_m;
    assign u_aru_crd_gen_cfg_if.slice_n = cfg_slt[cfg_idx_to_send_crd_gen].slice_n;

    // Output assignments for addr_calc
    assign u_aru_addr_calc_cfg_if.vld     = cfg_vld[cfg_idx_to_send_addr_calc] &&
                                            (cfg_sent[cfg_idx_to_send_addr_calc][1] == 1'b0);
    assign u_aru_addr_calc_cfg_if.ub_addr = cfg_slt[cfg_idx_to_send_addr_calc].ub_addr;
    assign u_aru_addr_calc_cfg_if.instr_idx = cfg_slt[cfg_idx_to_send_addr_calc].instr_idx;
    assign u_aru_addr_calc_cfg_if.slice_m = cfg_slt[cfg_idx_to_send_addr_calc].slice_m;
    assign u_aru_addr_calc_cfg_if.slice_n = cfg_slt[cfg_idx_to_send_addr_calc].slice_n;

endmodule
